package tdt4240.iddqd.sprites;

import org.anddev.andengine.engine.handler.physics.PhysicsHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.util.MathUtils;

public class Enemy extends AnimatedSprite {

	public PhysicsHandler physicsHandler;
	public boolean active=false;
	public boolean dead=false;
	public boolean damageable=true;
	public boolean stunned=false;
	public boolean aggroed=false;
	public boolean attacking=false;
	private boolean animated;

	public int damage = 10;
	public int health = 20;
	public int speed = 50;
	public Attack attack;
	public Rectangle activeAttack;


	public Enemy(float dx, float dy, TiledTextureRegion image){
		super(dx, dy, image);
		setCurrentTileIndex(0);
		animated = false;
		attack = new Attack(25f, 25f, 0.25f, 1.5f);
		physicsHandler = new PhysicsHandler(this);
		registerUpdateHandler(physicsHandler);
	}

	/**
	 * Play or stop animation of sprite
	 * @param bool If animation is wanted
	 * @param rotation The rotation of the player
	 */
	public void playAnimation(boolean bool, float rotation){
		if(animated ^ bool){
			animated = bool;
			if(animated){
				animate(100);	
			}else{
				stopAnimation();
			}
		}	
	}

	/**
	 * Calculate what action to take, mainly based on distance to player
	 * @param pl A player instance
	 */
	public void calculateAI(Player pl){
		if(!stunned){
			final float plX = pl.getX();
			final float plY = pl.getY();

			double distance = Math.sqrt(((getX()-plX)*(getX()-plX) + (getY()-plY)*(getY()-plY)));
			double x = (plX - getX()) / distance;
			double y = (plY - getY()) / distance;

			calculateMovement(distance, x, y);
			calculateAttack(distance, x, y);
		}
	}

	/**
	 * Determine if it is desirable to move
	 * @param distance Distance
	 * @param x X
	 * @param y Y
	 */
	private void calculateMovement(double distance, double x, double y){
		if((!aggroed && distance<200) || (aggroed && distance<500)){
			physicsHandler.setVelocity((float)x*speed, (float)y*speed);
			active=true;
			aggroed = true;
			float rotationInRad = (float) Math.atan2(-x, y);
			float rotation = MathUtils.radToDeg(rotationInRad);
			setRotation(rotation);
			playAnimation(true, rotation);
		}else{
			physicsHandler.setVelocity(0, 0);
			active=false;
			playAnimation(false, 0);
		}
	}

	/**
	 * Determine if it is desirable to attack
	 * @param distance Distance
	 * @param x X
	 * @param y Y
	 */
	private void calculateAttack(double distance, double x, double y){

		double temp = Math.sqrt(getHeightScaled()*getHeightScaled() + getWidthScaled()+getWidthScaled());

		if(distance < (temp + attack.height*1.2)){
			if(!attacking){
				attacking = true;
				float widthDisplacement = (getWidth()/2f)-(attack.width/2f);
				final Rectangle rect = new Rectangle(widthDisplacement,getHeight(), attack.width, attack.height);
				rect.setAlpha(0.3f);
				attachChild(rect);

				activeAttack = rect;

				TimerHandler spriteTimerHandler = new TimerHandler(attack.duration, new ITimerCallback()
				{                      
					@Override
					public void onTimePassed(final TimerHandler pTimerHandler)
					{
						detachChild(rect);
						activeAttack=null;
					}
				});

				TimerHandler cooldownTimerHandler = new TimerHandler(attack.cooldown, new ITimerCallback()
				{                      
					@Override
					public void onTimePassed(final TimerHandler pTimerHandler)
					{
						attacking=false;
					}
				});

				rect.registerUpdateHandler(spriteTimerHandler) ;
				registerUpdateHandler(cooldownTimerHandler);
			}
		}
	}

	/**
	 * Take damage from an attack
	 * @param pl A player instance
	 * @return If dead as a result of damage
	 */
	public boolean takeDamage(Player pl){
		if(damageable){
			playAnimation(false, 0);
			health-=pl.attack.damage;
			animate(100);
			damageable = false;
			stunned = true;
			aggroed = true;

			float x = getX()-pl.getX();
			float y = getY()-pl.getY();
			double norm = Math.sqrt(x*x + y*y);
			physicsHandler.setVelocity((float)(x/norm)*200, (float)(y/norm)*200);

			if(health<=0){
				dead=true;
			}else{
				TimerHandler hitstunTimerHandler = new TimerHandler(0.5f, new ITimerCallback()
				{                      
					@Override
					public void onTimePassed(final TimerHandler pTimerHandler)
					{
						damageable = true;
						stunned=false;
						physicsHandler.setVelocity(0,0);
						Enemy.this.unregisterUpdateHandler(pTimerHandler);
					}
				});
				this.registerUpdateHandler(hitstunTimerHandler);
			}
		}
		return dead;
	}


}
